//
//  E7GameCenter.mm
//  e7engine
//
//  Created by cc on 12-3-14.
//  Copyright (c) 2012年 PalmGame. All rights reserved.
//

///////////////////////////////////////////////
// typedef objective-c area.
#import "E7GameCenter.h"

#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>

CE7GameCenter* s_pE7GameCenter = NULL ;

// GKMatchmakerViewController
@interface GKMatchmakerViewController(LandscapeOnly)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
@end

@implementation GKMatchmakerViewController (LandscapeOnly)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    return ( UIInterfaceOrientationIsLandscape( interfaceOrientation ) );
}
@end
/*
// GCHelperDelegate
@protocol GCHelperDelegate 
- (void)matchStarted;
- (void)matchEnded;
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID;
- (void)inviteReceived;
@end
*/
// GCHelper
@interface GCHelper : NSObject <GKMatchmakerViewControllerDelegate, GKMatchDelegate>
//@interface GCHelper : UIViewController <GKMatchmakerViewControllerDelegate, GKMatchDelegate, GKLeaderboardViewControllerDelegate>
{
    BOOL gameCenterAvailable;
    BOOL userAuthenticated;
    
    UIViewController *presentingViewController;
    GKMatch *match;
    BOOL matchStarted;
//    id <GCHelperDelegate> delegate;
    NSMutableDictionary *playersDict;
    GKInvite *pendingInvite;
    NSArray *pendingPlayersToInvite;
    
}

@property (assign, readonly) BOOL gameCenterAvailable;
@property (retain) UIViewController *presentingViewController;
@property (retain) GKMatch *match;
//@property (assign) id <GCHelperDelegate> delegate;
@property (retain) NSMutableDictionary *playersDict;
@property (retain) GKInvite *pendingInvite;
@property (retain) NSArray *pendingPlayersToInvite;

+ (GCHelper *)sharedInstance;
- (void)authenticateLocalUser;
//- (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers viewController:(UIViewController *)viewController delegate:(id<GCHelperDelegate>)theDelegate;
- (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers ;
@end

#pragma mark implementation

@implementation GCHelper
@synthesize gameCenterAvailable;
@synthesize presentingViewController;
@synthesize match;
//@synthesize delegate;
@synthesize playersDict;
@synthesize pendingInvite;
@synthesize pendingPlayersToInvite;

#pragma mark Initialization

static GCHelper *sharedHelper = nil;
+ (GCHelper *) sharedInstance {
    if (!sharedHelper) {
        sharedHelper = [[GCHelper alloc] init];
    }
    return sharedHelper;
}

- (BOOL)isGameCenterAvailable {
	// check for presence of GKLocalPlayer API
	Class gcClass = (NSClassFromString(@"GKLocalPlayer"));
	
	// check if the device is running iOS 4.1 or later
	NSString *reqSysVer = @"4.1";
	NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
	BOOL osVersionSupported = ([currSysVer compare:reqSysVer 
                                           options:NSNumericSearch] != NSOrderedAscending);
	
	return (gcClass && osVersionSupported);
}

- (id)init {
    if ((self = [super init])) {
        gameCenterAvailable = [self isGameCenterAvailable];
        if (gameCenterAvailable)
        {
            NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
            [nc addObserver:self 
                   selector:@selector(authenticationChanged) 
                       name:GKPlayerAuthenticationDidChangeNotificationName 
                     object:nil];
        }
    }
    return self;
}

#pragma mark Internal functions

- (void)authenticationChanged {    
    
    if ([GKLocalPlayer localPlayer].isAuthenticated && !userAuthenticated) {
        NSLog(@"Authentication changed: player authenticated.");
        userAuthenticated = TRUE;  
        
        [GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
            
            NSLog(@"Received invite");
            self.pendingInvite = acceptedInvite;
            self.pendingPlayersToInvite = playersToInvite;
//            [delegate inviteReceived];
            s_pE7GameCenter->InviteReceived() ;
            
        };
        
    } else if (![GKLocalPlayer localPlayer].isAuthenticated && userAuthenticated) {
        NSLog(@"Authentication changed: player not authenticated");
        userAuthenticated = FALSE;
    }
    
}

- (void)lookupPlayers {
    
    NSLog(@"Looking up %d players...", match.playerIDs.count);
    [GKPlayer loadPlayersForIdentifiers:match.playerIDs withCompletionHandler:^(NSArray *players, NSError *error) {
        
        if (error != nil) {
            NSLog(@"Error retrieving player info: %@", error.localizedDescription);
            matchStarted = NO;
//            [delegate matchEnded];
            s_pE7GameCenter->MatchEnd() ;
        } else {
            
            // Populate players dict
            self.playersDict = [NSMutableDictionary dictionaryWithCapacity:players.count];
            for (GKPlayer *player in players) {
                NSLog(@"Found player: %@", player.alias);
                [playersDict setObject:player forKey:player.playerID];
            }
            
            // Notify delegate match can begin
            matchStarted = YES;
//            [delegate matchStarted];
            s_pE7GameCenter->MatchStart() ;

        }
    }];
    
}

#pragma mark User functions

- (void)authenticateLocalUser { 
    
    if (!gameCenterAvailable) return;
    
    NSLog(@"Authenticating local user...");
    if ([GKLocalPlayer localPlayer].authenticated == NO) {     
        [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:nil];        
    } else {
        NSLog(@"Already authenticated!");
    }
}

//- (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers viewController:(UIViewController *)viewController delegate:(id<GCHelperDelegate>)theDelegate {
- (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers {
    
    if (!gameCenterAvailable) return;
    
    matchStarted = NO;
    self.match = nil;
//    self.presentingViewController = viewController;
//    delegate = theDelegate;
    
    if (pendingInvite != nil) {
        
        [presentingViewController dismissModalViewControllerAnimated:NO];
        GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:pendingInvite] autorelease];
        mmvc.matchmakerDelegate = self;
        [presentingViewController presentModalViewController:mmvc animated:YES];
        
        self.pendingInvite = nil;
        self.pendingPlayersToInvite = nil;
        
    } else {
        
        [presentingViewController dismissModalViewControllerAnimated:NO];
        GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease]; 
        request.minPlayers = minPlayers;     
        request.maxPlayers = maxPlayers;
        request.playersToInvite = pendingPlayersToInvite;
        
        GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];    
        mmvc.matchmakerDelegate = self;
        
        [presentingViewController presentModalViewController:mmvc animated:YES];
        
        self.pendingInvite = nil;
        self.pendingPlayersToInvite = nil;
        
    }
    
}

#pragma mark GKMatchmakerViewControllerDelegate

// The user has cancelled matchmaking
- (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController {
    [presentingViewController dismissModalViewControllerAnimated:YES];
}

// Matchmaking has failed with an error
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error {
    [presentingViewController dismissModalViewControllerAnimated:YES];
    NSLog(@"Error finding match: %@", error.localizedDescription);    
}

// A peer-to-peer match has been found, the game should start
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)theMatch {
    [presentingViewController dismissModalViewControllerAnimated:YES];
    self.match = theMatch;
    match.delegate = self;
    if (!matchStarted && match.expectedPlayerCount == 0) {
        NSLog(@"Ready to start match!");
        [self lookupPlayers];
    }
}

#pragma mark GKMatchDelegate

// The match received data sent from the player.
- (void)match:(GKMatch *)theMatch didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
    
    if (match != theMatch) return;

    sProtocolID* pMsg = (sProtocolID*)[data bytes] ;
//    [delegate match:theMatch didReceiveData:data fromPlayer:playerID];
    s_pE7GameCenter->RecvMessage(pMsg->cMsgID, (void*)[data bytes]) ;
}

// The player state changed (eg. connected or disconnected)
- (void)match:(GKMatch *)theMatch player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state {
    
    if (match != theMatch) return;
    
    switch (state) {
        case GKPlayerStateConnected:
        {
            // handle a new player connection.
            NSLog(@"Player connected!");
            
            if (!matchStarted && theMatch.expectedPlayerCount == 0)
            {
                NSLog(@"Ready to start match!");
                [self lookupPlayers];
            }
            
        } break; 
        case GKPlayerStateDisconnected:
        {
            // a player just disconnected. 
            NSLog(@"Player disconnected!");
            matchStarted = NO;
//            [delegate matchEnded];
            s_pE7GameCenter->MatchEnd() ;
        } break;
    }                 
    
}

// The match was unable to connect with the player due to an error.
- (void)match:(GKMatch *)theMatch connectionWithPlayerFailed:(NSString *)playerID withError:(NSError *)error {
    
    if (match != theMatch) return;
    
    NSLog(@"Failed to connect to player with error: %@", error.localizedDescription);
    matchStarted = NO;
//    [delegate matchEnded];
    s_pE7GameCenter->MatchEnd() ;
}

// The match was unable to be established with any players due to an error.
- (void)match:(GKMatch *)theMatch didFailWithError:(NSError *)error {
    
    if (match != theMatch) return;
    
    NSLog(@"Match failed with error: %@", error.localizedDescription);
    matchStarted = NO;
//    [delegate matchEnded];
    s_pE7GameCenter->MatchEnd() ;
}

@end

///////////////////////////////////////////////
// c++ area.

CE7GameCenter::CE7GameCenter(RecvMsgCallBack func)
{
    m_funcRecvMsg = func ;
    printf("new CE7GameCenter === \n") ;
    [[GCHelper sharedInstance] authenticateLocalUser] ;

//    [[GCHelper sharedInstance] findMatchWithMinPlayers:2 maxPlayers:2] ;
}

CE7GameCenter::~CE7GameCenter()
{
    [[GCHelper sharedInstance] dealloc] ;
}

void CE7GameCenter::InviteReceived()
{
    printf("enter CE7GameCenter::InviteReceived\n") ;
}

void CE7GameCenter::MatchStart()
{
    printf("enter CE7GameCenter::MatchStart\n") ;
}

void CE7GameCenter::MatchEnd()
{
    printf("enter CE7GameCenter::MatchEnd\n") ;
}

void CE7GameCenter::RecvMessage(MSGID eid, void* buf)
{
    printf("enter CE7GameCenter::RecvMessage\n") ;
    m_funcRecvMsg(eid, buf) ;
}

void CE7GameCenter::SendMessage(const void* buf, const int len)
{
    printf("enter CE7GameCenter::SendMessage\n") ;
    NSData* data = [NSData dataWithBytes:buf length:len] ;

    NSError *error ;
    bool success = [[GCHelper sharedInstance].match sendDataToAllPlayers:data
                                                            withDataMode:GKMatchSendDataReliable
                                                                   error:&error] ;
    if (!success)
    {
        printf("Error SendMessage\n") ;
        MatchEnd() ;
    }
}























